unit Chromium4D.Render.Environment;

interface

  uses ceflib, Chromium4D.Core;

type

  TSyRenderEnvConstants = class
  public
    const
      STR_ADDRESS   = 'address';
      STR_ARGS      = 'args';
      STR_ARGV      = 'argv';
      STR_BINDING   = 'binding';
      STR_CACHE     = '_cache';
      STR_CHANGE    = 'change';
      STR_DIR       = 'dir';
      STR_EMIT      = 'emit';
      STR_EXEC_ARGV = 'execArgv';
      STR_EXEC_PATH = 'execPath';
      STR_FAMILY    = 'family';
      STR_FILE      = 'file';
      STR_IDLE      = 'idle';
      STR_INTERNAL  = 'internal';
      STR_IPv4      = 'IPv4';
      STR_IPv6      = 'IPv6';
      STR_IRQ       = 'irq';
      STR_JUNCTION  = 'junction';
      STR_LENGTH    = 'length';
      STR_MAC       = 'mac';
      STR_MODEL     = 'model';
      STR_MODULES   = 'modules';
      STR_MODULE_LOAD_LIST = 'moduleLoadList';
      STR_NETMASK   = 'netmask';
      STR_NICE      = 'nice';
      STR_ONCHANGE  = 'onchange';
      STR_ONCOMPLETE= 'oncomplete';
      STR_ONSTOP    = 'onstop';
      STR_PROTOTYPE = 'prototype';
      STR_RENAME    = 'rename';
      STR_RSS       = 'rss';
      STR_SCOPEID   = 'scopeid';
      STR_SPEEDD    = 'speed';
      STR_SYS       = 'sys';
      STR_TIMES     = 'times';
      STR_UNCAUGHTEXCEPTION = 'uncaughtException';
      STR_UNKNOWN   = '<unknown>';
      STR_USER      = 'user';
      STR_WRAP      = '_wrap';
      STR_NOT_IMPLEMENTED = 'Not Implemented.';
  end;

  TSyRenderEnvArray = record
  public
    module_load_list  : ICefv8Value;
    array_buffer_flags: ICefv8Value;
  public
    class function Create: TSyRenderEnvArray; static;
    procedure Free;
  end;

  TSyRenderEnvObject = record
  public
    process      : ICefv8Value;
    binding_cache: ICefv8Value;
    ptype_buffer : ICefv8Value;
  public
    class function Create: TSyRenderEnvObject; static;
    procedure Free;
    procedure Setptype_buffer(value: ICefv8Value);
  end;

  TSyRenderEnvCallBack = record
  public
    op_new   : ICefv8Value;
    op_throw : ICefv8Value;
    new_error: ICefv8Value;
    ctor_fs_stats: ICefv8Value;
  public
    class function Create: TSyRenderEnvCallBack; static;
    procedure Free;
  end;

  TSyRenderEnvironment = class
  private
    const
      SCRIPT_NEW =
          '(function(){'  + #10#13
        + '  var obj = Object.create(this.prototype);' + #10#13
        + '  var res = this.apply(obj, arguments);' + #10#13
        + '  return (typeof res === ''object'' && res) || obj;' + #10#13
        + '});';

      SCRIPT_ERROR =
          '(function(str){'  + #10#13
        + '  return new Error(str);' + #10#13
        + '});';

      SCRIPT_THROW =
          '(function(str){'  + #10#13
        + '  throw new Error(str);' + #10#13
        + '});';

  private
    FProcess: TSyChromiumProcess;
    FContextId: string;

    FPathExec: string;
    FPathPage: string;
    FUrlFrame: string;

    FEnvObject  : TSyRenderEnvObject;
    FEnvCallback: TSyRenderEnvCallBack;
    FEnvArray   : TSyRenderEnvArray;
  public
    constructor Create(AProcess: TSyChromiumProcess; AContext: ICefv8Context); virtual;
    destructor Destroy; overload;

    function Setup(execPath, pagePath, frameUrl: string; process: ICefv8Value): Boolean;
  public
    property EnvObject: TSyRenderEnvObject read FEnvObject;
    property EnvCallback: TSyRenderEnvCallBack read FEnvCallback;
    property EnvEnvArray: TSyRenderEnvArray read FEnvArray;
  end;


implementation

  uses Chromium4D.Render.Process;

type
  TSyRenderEnvironmentHelper = class helper for TSyRenderEnvironment
  protected
    function GetRenderProcess: TSyRenderProcess;
  end;

{ TSyRenderEnvironment }

constructor TSyRenderEnvironment.Create(AProcess: TSyChromiumProcess; AContext: ICefv8Context);
var
  exception: ICefV8Exception;
begin
  FProcess   := AProcess;
  FContextId := GetRenderProcess.CreateIDForContext(AContext);
  GetRenderProcess.EnvironmentMapper.Add(FContextId, Self);

  FEnvObject  := TSyRenderEnvObject.Create;
  FEnvCallback:= TSyRenderEnvCallBack.Create;
  FEnvArray   := TSyRenderEnvArray.Create;

  // new
  AContext.Eval(SCRIPT_NEW, FEnvCallback.op_new, exception);
  // new Error(str)
  AContext.Eval(SCRIPT_ERROR, FEnvCallback.new_error, exception);
  // throw
  AContext.Eval(SCRIPT_THROW, FEnvCallback.op_throw, exception);
end;

destructor TSyRenderEnvironment.Destroy;
begin
  FEnvObject.Free;
  FEnvCallback.Free;
  FEnvArray.Free;
  FContextId := '';
end;

function TSyRenderEnvironment.Setup(execPath, pagePath, frameUrl: string; process: ICefv8Value): Boolean;
var
  vExecPath, vPagePath, argsNode, binding: ICefv8Value;
begin
  FPathExec := execPath;
  FPathPage := pagePath;
  FUrlFrame := frameUrl;

  FEnvObject.process := process;

  // argv[0] represents application path
  // argv[1] represents page path
  vExecPath := TCefV8ValueRef.NewString(execPath);
  vPagePath := TCefV8ValueRef.NewString(pagePath);

  // process.argv
  argsNode := TCefV8ValueRef.NewArray(2);
  argsNode.SetValueByIndex(0, vExecPath);
  argsNode.SetValueByIndex(1, vPagePath);
  process.SetValueByKey(TSyRenderEnvConstants.STR_ARGV, argsNode, V8_PROPERTY_ATTRIBUTE_NONE);

  // process.execArgv
  argsNode := TCefV8ValueRef.NewArray(2);
  argsNode.SetValueByIndex(0, vExecPath);
  argsNode.SetValueByIndex(1, vPagePath);
  process.SetValueByKey(TSyRenderEnvConstants.STR_EXEC_ARGV, argsNode, V8_PROPERTY_ATTRIBUTE_NONE);

  // process.execPath
  process.SetValueByKey(TSyRenderEnvConstants.STR_EXEC_PATH, vExecPath, V8_PROPERTY_ATTRIBUTE_NONE);

  // process.moduleLoadList
  process.SetValueByKey(TSyRenderEnvConstants.STR_MODULE_LOAD_LIST, FEnvArray.module_load_list, [V8_PROPERTY_ATTRIBUTE_READONLY]);

  // variables not defined in Node.js

  // process.binding._cache
  binding := process.GetValueByKey(TSyRenderEnvConstants.STR_BINDING);
  binding.SetValueByKey(TSyRenderEnvConstants.STR_CACHE, FEnvObject.binding_cache, V8_PROPERTY_ATTRIBUTE_NONE);
end;

{ TSyRenderEnvironmentHelper }

function TSyRenderEnvironmentHelper.GetRenderProcess: TSyRenderProcess;
begin
  Result := TSyRenderProcess(FProcess);
end;

{ TSyRenderEnvArray }

class function TSyRenderEnvArray.Create: TSyRenderEnvArray;
begin
  Result.module_load_list := TCefv8ValueRef.NewArray(0);
end;

procedure TSyRenderEnvArray.Free;
begin
  module_load_list  := nil;
  array_buffer_flags:= nil;
end;

{ TSyRenderEnvObject }

class function TSyRenderEnvObject.Create: TSyRenderEnvObject;
begin
  Result.binding_cache := TCefv8ValueRef.NewObject(nil);
  Result.process       := nil;
  Result.ptype_buffer  := nil;
end;

procedure TSyRenderEnvObject.Free;
begin
  process      := nil;
  binding_cache:= nil;
end;

procedure TSyRenderEnvObject.Setptype_buffer(value: ICefv8Value);
begin
  ptype_buffer := value;
end;

{ TSyRenderEnvCallBack }

class function TSyRenderEnvCallBack.Create: TSyRenderEnvCallBack;
begin

end;

procedure TSyRenderEnvCallBack.Free;
begin
  op_new       := nil;
  op_throw     := nil;
  new_error    := nil;
  ctor_fs_stats:= nil;
end;

end.
